//
// Copyright (C) OpenSim Ltd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, see <http://www.gnu.org/licenses/>.
//
#include <cstdio>
#include <cstring>
#include <sstream>
#include "inet/queueing/compat/cpacketqueue.h"

namespace inet {
namespace queueing {

using std::ostream;

Register_Class(cPacketQueue);

cPacketQueue::cPacketQueue(const cPacketQueue& queue) : cQueue(queue)
{
    copy(queue);
}

void cPacketQueue::copy(const cPacketQueue& queue)
{
    bitLength = queue.bitLength;
}

cPacketQueue& cPacketQueue::operator=(const cPacketQueue& queue)
{
    if (this == &queue)
        return *this;
    cQueue::operator=(queue);
    copy(queue);
    return *this;
}

std::string cPacketQueue::str() const
{
    if (isEmpty())
        return std::string("empty");
    std::stringstream out;
    out << "len=" << getLength() << ", " << getBitLength() << " bits (" << getByteLength() << " bytes)";
    return out.str();
}

void cPacketQueue::parsimPack(cCommBuffer *buffer) const
{
#ifndef WITH_PARSIM
    throw cRuntimeError(this, E_NOPARSIM);
#else
    cQueue::parsimPack(buffer);
    buffer->pack(bitLength);
#endif
}

void cPacketQueue::parsimUnpack(cCommBuffer *buffer)
{
#ifndef WITH_PARSIM
    throw cRuntimeError(this, E_NOPARSIM);
#else
    cQueue::parsimUnpack(buffer);
    buffer->unpack(bitLength);
#endif
}

void cPacketQueue::addLength(cPacket *pkt)
{
    bitLength += pkt->getBitLength();
}

cPacket *cPacketQueue::checkPacket(cObject *obj)
{
    cPacket *pkt = dynamic_cast<cPacket *>(obj);
    if (!pkt)
        throw cRuntimeError(this, "insert...(): Cannot cast (%s)%s to cPacket", obj->getClassName(), obj->getFullName());
    return pkt;
}

void cPacketQueue::insert(cPacket *pkt)
{
    cQueue::insert(pkt);
    addLength(pkt);
}

void cPacketQueue::insertBefore(cPacket *where, cPacket *pkt)
{
    cQueue::insertBefore(where, pkt);
    addLength(pkt);
}

void cPacketQueue::insertAfter(cPacket *where, cPacket *pkt)
{
    cQueue::insertAfter(where, pkt);
    addLength(pkt);
}

cPacket *cPacketQueue::remove(cPacket *pkt)
{
    return (cPacket *)remove((cObject *)pkt);
}

cPacket *cPacketQueue::pop()
{
    cPacket *pkt = (cPacket *)cQueue::pop();
    if (pkt)
        bitLength -= pkt->getBitLength();
    return pkt;
}

void cPacketQueue::clear()
{
    cQueue::clear();
    bitLength = 0;
}

void cPacketQueue::insert(cObject *obj)
{
    insert(checkPacket(obj));
}

void cPacketQueue::insertBefore(cObject *where, cObject *obj)
{
    insertBefore(checkPacket(where), checkPacket(obj));
}

void cPacketQueue::insertAfter(cObject *where, cObject *obj)
{
    insertAfter(checkPacket(where), checkPacket(obj));
}

cObject *cPacketQueue::remove(cObject *obj)
{
    cPacket *pkt = (cPacket *)cQueue::remove(obj);
    if (pkt)
        bitLength -= pkt->getBitLength();
    return pkt;
}

}  // namespace queueing
}  // namespace inet

